home *** CD-ROM | disk | FTP | other *** search
- /* revamped version by Loren J. Rittle. Thanks Loren !! */
-
- /* I guess I should start to put my sources into RCS........ */
-
- #include <exec/types.h>
- #include <exec/libraries.h>
- #include <exec/execbase.h>
-
- #include <inline/exec.h>
- #include <libraries/dosextens.h>
- #include <proto/intuition.h>
- #include <limits.h>
- #include "kprintf.h"
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <sys/wait.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <arpa/nameser.h>
- #include <resolv.h>
-
- #include <sys/syscall.h>
- #ifdef BASECRT0
- #include <sys/exec.h>
- #endif /* BASECRT0 */
-
- /* get the current revision number. Version control is automatically done by
- * OpenLibrary(), I just have to check the revision number
- */
- #undef IX_VERSION
- #include "version.h"
-
- #define MSTRING(x) STRING(x)
- #define STRING(x) #x
-
- struct Library *ixemulbase;
-
- static int start_stdio(int, char **, char **);
- static int exec_entry (struct Library *ixembase, int argc, char *argv[], char *env[]);
- static int ENTRY();
-
- int ix_exec_entry(int argc, char **argv, char **environ, int *real_errno,
- int (*main)(int, char **, char **));
- int ix_startup(char *aline, int alen, int expand,
- char *wb_default_window, unsigned main, int *real_errno);
- void ix_get_vars2 ();
- void monstartup(char *lowpc, char *highpc);
- void __init_stk_limit(void **limit, unsigned long argbytes);
-
- /*
- * Have to take care.. I may not use any library functions in this file,
- * since they are exactly then used, when the library itself couldn't be
- * opened...
- */
-
- extern int main();
-
- /*
- * This is the first code executed. Note that a_magic has to be at
- * a known offset from the start of the code section in order for
- * execve() to know that the program that it is starting uses the
- * ixemul library.
- *
- * The first instruction used to be a "jmp pc@(_ENTRY)", which when
- * assembled by gas 2.5.2 produces an 8 byte 68020 PC relative jump
- * rather than the desired 68000 short PC relative jump. Changing
- * it to "jmp pc@(_ENTRY:W)" generated the right instruction but
- * a bad jmp offset. So we use "jra _ENTRY" which seems to work
- * fine on all m68k. However, since programs are now in use
- * linked with crt0 files with the 8 byte instruction, we need to
- * maintain the hack in execve() that allows either jmp, and now
- * the jra, and we need to ensure that a 16 bit displacement is
- * required to reach ENTRY() or else we will have to add yet
- * another pattern to match in execve().
- *
- */
-
-
- asm("
- .text
-
- jra _ENTRY | by default jump to normal AmigaDOS startup
- .align 2 | ensure exec starts at byte offset 4
-
- | this is a struct exec, for now only OMAGIC is supported
- .globl exec
- exec:
- .word ___machtype | a_mid
- .word 0407 | a_magic = OMAGIC
- .long ___text_size | a_text
- .long ___data_size | a_data
- .long ___bss_size | a_bss
- .long 0 | a_syms
- .long _exec_entry | a_entry
- .long 0 | a_trsize
- .long 0 | a_drsize
-
- | word alignment is guaranteed
- ");
-
- extern int expand_cmd_line; /* expand wildcards ? */
- int h_errno = 0; /* networking error code */
- struct __res_state _res = { /* Resolver state default settings */
- RES_TIMEOUT, /* retransmition time interval */
- 4, /* number of times to retransmit */
- RES_DEFAULT, /* options flags */
- 1 /* number of name servers */
- };
- int _res_socket = -1; /* resolv socket used for communications */
- char *default_wb_window = 0; /* Default Workbench output window name. */
- int errno = 0; /* error results from the library come in here.. */
- char *_ctype_; /* we use a pointer into the library, this is static anyway */
- int sys_nerr; /* number of system error codes */
- struct ExecBase *SysBase;
- struct Library *DOSBase;
- struct __sFILE **__sF;
- static char *dummy_environ = 0;
- char **environ = { &dummy_environ }; /* this is a default for programs not started via exec_entry */
- char *__progname = "";
-
- extern void *__stk_limit;
- extern unsigned long __stk_argbytes;
-
- #if defined(DEBUG_VERSION)
- static inline u_int __geta4(void)
- {
- u_int res;
-
- asm volatile ("movel a4,%0" : "=g" (res));
- return res;
- }
- #endif
-
- static void ix_panic(const char *msg, ...)
- {
- struct IntuitionBase *IntuitionBase;
- va_list ap;
-
- /* Use address 4 instead of the SysBase global as globals may not yet be
- available (a4-handling) */
- #undef EXEC_BASE_NAME
- #define EXEC_BASE_NAME *(void **)4
-
- va_start(ap, msg);
- if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0)))
- {
- struct EasyStruct panic = {
- sizeof(struct EasyStruct),
- 0,
- "",
- (char *)msg,
- "Abort"
- };
-
- EasyRequestArgs(NULL, &panic, NULL, ap);
-
- CloseLibrary ((struct Library *) IntuitionBase);
- }
- va_end(ap);
-
- #undef EXEC_BASE_NAME
- #define EXEC_BASE_NAME SysBase
- }
-
-
- #ifdef BASECRT0
- extern int __datadata_relocs();
- extern int __data_size, __bss_size;
-
- #ifdef RCRT0
- /* have to do this this way, or it is done base-relative.. */
- static inline int dbsize()
- {
- int res;
- KPRINTF (("enter dbsize()\n"));
- asm ("movel #___data_size,%0; addl #___bss_size,%0" : "=r" (res));
- return res;
- }
-
- static void inline
- ix_resident (void *base, int num, int a4, int size, void *relocs)
- {
- typedef void (*func)(int, int, int, void *);
-
- KPRINTF (("enter ix_resident()\n"));
- ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4, size, relocs);
- }
-
- #else
- static void inline
- ix_resident (void *base, int num, int a4)
- {
- typedef void (*func)(int, int);
-
- KPRINTF (("enter ix_resident()\n"));
- ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4);
- }
- #endif
- #endif /* BASECRT0 */
-
- static int
- exec_entry (struct Library *ixembase, int argc, char *argv[], char *env[])
- {
- #ifdef BASECRT0
- register int a4;
- /* needed, so that data can be accessed. ix_resident might change this
- again afterwards */
- asm volatile ("lea ___a4_init,a4" : "=r" (a4) : "0" (a4));
- asm volatile ("movel a4,%0" : "=r" (a4) : "0" (a4));
-
- KPRINTF (("enter exec_entry()\n"));
- #ifdef RCRT0
- ix_resident (ixembase, 4, a4, dbsize(), __datadata_relocs);
- #else
- ix_resident (ixembase, 2, a4);
- #endif
- #endif /* BASECRT0 */
- ixemulbase = ixembase;
- if (ixemulbase->lib_Version < IX_VERSION)
- {
- ix_panic("Need at least version " MSTRING (IX_VERSION) " of " IX_NAME ".");
- return W_EXITCODE(20, 0);
- }
- return ix_exec_entry (argc, argv, env, &errno, start_stdio);
- }
-
- /* this thing is best done with sprintf else, but it has to work without the
- * library as well ;-(
- */
- __inline static char *
- itoa (int num)
- {
- short snum = num;
-
- /* how large can a long get...?? */
- /* Answer (by ljr): best method to use (in terms of portability)
- involves number theory. The exact number of decimal digits
- needed to store a given number of binary digits is
-
- ceiling ( number_of_binary_digits * log(2) / log(10) )
- or
- ceiling ( number_of_binary_digits * 0.301029996 )
-
- Since sizeof evaluates to the number of bytes a given type takes
- instead of the number of bits, we need to multiply sizeof (type) by
- CHAR_BIT to obtain the number of bits. Since an array size specifier
- needs to be integer type, we multiply by 302 and divide by 1000 instead
- of multiplying by 0.301029996. Finally, we add 1 for the null terminator
- and 1 because we want the ceiling of the function instead of the floor.
- Funny thing about this whole affair is that you really wanted to know
- the size a short could expand to be and not a long... :-) I know
- comments get out of date, etc. The nice thing about this method is
- that the size of the array is picked at compile time based upon the
- number of bytes really needed by the local C implementation. */
- static char buf[sizeof snum * CHAR_BIT * 302 / 1000 + 1 + 1];
- char *cp;
-
- KPRINTF (("enter itoa()\n"));
- buf[sizeof buf - 1] = 0;
- cp = &buf[sizeof buf - 1];
- do
- {
- *--cp = (snum % 10) + '0';
- snum /= 10;
- } while (snum);
-
- return cp;
- }
-
- __inline static char *
- pstrcpy (char *start, char *arg)
- {
- KPRINTF (("enter pstrcpy()\n"));
- while ((*start++ = *arg++)) ;
- return start - 1;
- }
-
- /* Note: This routine must be far enough away from the start of code
- so that the PC relative offset won't fit in a byte and the assembler
- will generate the right instruction pattern that execve() is looking
- for to know that this is a program that uses the ixemul.library. */
-
- static int
- ENTRY (void)
- {
- register unsigned char *rega0 asm("a0");
- register unsigned long regd0 asm("d0");
- #ifdef BASECRT0
- register int a4;
- #endif /* BASECRT0 */
- struct Library *ibase;
- UBYTE *aline = rega0;
- ULONG alen = regd0;
- int res;
-
- #ifdef BASECRT0
- /* needed, so that data can be accessed. ix_resident() might change this
- again afterwards */
- asm volatile ("lea ___a4_init,a4" : "=r" (a4) : "0" (a4));
- asm volatile ("movel a4,%0" : "=r" (a4) : "0" (a4));
- #endif /* BASECRT0 */
-
- KPRINTF (("enter ENTRY()\n"));
- KPRINTF (("alen = %ld; aline = '%s'\n", alen, aline));
-
- /* Use address 4 instead of the SysBase global as globals may not yet be
- available (a4-handling) */
- #undef EXEC_BASE_NAME
- #define EXEC_BASE_NAME *(void **)4
-
- ibase = OpenLibrary (IX_NAME, IX_VERSION);
- KPRINTF (("ibase = %lx\n", ibase));
- if (ibase)
- {
- #ifdef BASECRT0
- #ifdef RCRT0
- ix_resident (ibase, 4, a4, dbsize(), __datadata_relocs);
- #else
- ix_resident (ibase, 2, a4);
- #endif
- KPRINTF (("ix_resident: a4 = $%lx\n", __geta4()));
- #endif /* BASECRT0 */
-
- ixemulbase = ibase;
-
- KPRINTF (("calling ix_startup()\n"));
- res = ix_startup (aline, alen,
- expand_cmd_line, default_wb_window, (int)start_stdio, &errno);
-
- CloseLibrary (ixemulbase);
- }
- else
- {
- struct Process *me = (struct Process *)((*(struct ExecBase **)4)->ThisTask);
-
- ix_panic("Need at least version " MSTRING (IX_VERSION) " of " IX_NAME ".");
-
- /* quickly deal with the WB startup message, as the library couldn't do
- * this for us. Nothing at all is done that isn't necessary to just shutup
- * workbench..*/
- if (! me->pr_CLI)
- {
- Forbid ();
- ReplyMsg ((WaitPort (& me->pr_MsgPort), GetMsg (& me->pr_MsgPort)));
- }
-
- res = 20;
- }
- return (res);
- #undef EXEC_BASE_NAME
- #define EXEC_BASE_NAME SysBase
- }
-
- void ix_get_variables(int from_vfork_setup_child)
- {
- /* more to follow ;-) */
- ix_get_vars2 (11, &_ctype_, &sys_nerr, &SysBase, &DOSBase, &__sF,
- &environ, (from_vfork_setup_child ? &environ : NULL),
- (from_vfork_setup_child ? &errno : NULL), &h_errno,
- &_res, &_res_socket);
- }
-
- int
- start_stdio (int argc, char **argv, char **env)
- {
- int res;
- #ifndef BASECRT0
- extern void etext ();
- extern void _mcleanup (void);
- #else /* BASECRT0 */
-
- KPRINTF (("start_stdio1: a4 = $%lx\n", __geta4()));
- #endif /* BASECRT0 */
-
- #ifdef DEBUG_VERSION
- KPRINTF (("enter start_stdio()\n"));
- KPRINTF (("argc = %ld (args follow)\n", argc));
- {
- int i;
- for (i = 0; i < argc; i++)
- {
- KPRINTF (("argv[%ld] = '%s'\n", i, argv[i]));
- }
- }
- #endif
-
- ix_get_variables(0);
- environ = env;
-
- #ifndef BASECRT0
- #ifdef MCRT0
- atexit(_mcleanup);
- monstartup((char *)start_stdio, (char *)etext);
- #endif
- #endif /* not BASECRT0 */
-
-
- /*
- * Set the limit variable to finish the initialization of the stackextend code.
- */
- __init_stk_limit(&__stk_limit,__stk_argbytes);
-
- if (argv[0])
- if ((__progname = strrchr(argv[0], '/')) == NULL)
- __progname = argv[0];
- else
- ++__progname;
- res = main (argc, argv, env);
- return res;
- }
-
- #ifndef BASECRT0
- #ifdef CRT0
- /*
- * null mcount and moncontrol,
- * just in case some routine is compiled for profiling
- */
- asm(".globl mcount");
- asm(".globl _moncontrol");
- asm("_moncontrol:");
- asm("mcount: rts");
- #endif /* CRT0 */
- #endif /* not BASECRT0 */
-
- #ifndef BASECRT0
- #ifdef MCRT0
- #include "gmon.c"
- #endif
- #endif /* not BASECRT0 */
-